Add Levenshtein distance implementation
authorDavid Davidović <geosoft.corp@gmail.com>
Wed, 24 Dec 2014 03:27:07 +0000 (04:27 +0100)
committerDavid Davidović <geosoft.corp@gmail.com>
Wed, 24 Dec 2014 03:53:27 +0000 (04:53 +0100)
Copy lev_distance.rs verbatim from Rust since str::lev_distance has been
deprecated by rust-lang/rust@9b99436 with no replacement and change code
to use it instead of the deprecated function

src/bin/cargo.rs
src/cargo/util/lev_distance.rs [new file with mode: 0644]
src/cargo/util/mod.rs

index 9a96d646912f199b7caba2cd892f4e455dadf869..7d05e9ccbe3cbf9de3ba9871142d7d8766ab10b2 100644 (file)
@@ -13,7 +13,7 @@ use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
 
 use cargo::{execute_main_without_stdin, handle_error, shell};
 use cargo::core::MultiShell;
-use cargo::util::{CliError, CliResult};
+use cargo::util::{CliError, CliResult, lev_distance};
 
 #[deriving(RustcDecodable)]
 struct Flags {
@@ -139,7 +139,7 @@ fn find_closest(cmd: &str) -> Option<String> {
                             // doing it this way (instead of just .min_by(|c| c.lev_distance(cmd)))
                             // allows us to only make suggestions that have an edit distance of
                             // 3 or less
-                            .map(|c| (c.lev_distance(cmd), c))
+                            .map(|c| (lev_distance(c.as_slice(), cmd), c))
                             .filter(|&(d, _): &(uint, &String)| d < 4u)
                             .min_by(|&(d, _)| d) {
         Some((_, c)) => {
diff --git a/src/cargo/util/lev_distance.rs b/src/cargo/util/lev_distance.rs
new file mode 100644 (file)
index 0000000..24e9883
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cmp;
+
+pub fn lev_distance(me: &str, t: &str) -> uint {
+    if me.is_empty() { return t.chars().count(); }
+    if t.is_empty() { return me.chars().count(); }
+
+    let mut dcol = Vec::from_fn(t.len() + 1, |x| x);
+    let mut t_last = 0;
+
+    for (i, sc) in me.chars().enumerate() {
+
+        let mut current = i;
+        dcol[0] = current + 1;
+
+        for (j, tc) in t.chars().enumerate() {
+
+            let next = dcol[j + 1];
+
+            if sc == tc {
+                dcol[j + 1] = current;
+            } else {
+                dcol[j + 1] = cmp::min(current, next);
+                dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1;
+            }
+
+            current = next;
+            t_last = j;
+        }
+    }
+
+    dcol[t_last + 1]
+}
+
+#[test]
+fn test_lev_distance() {
+    use std::char::{ from_u32, MAX };
+    // Test bytelength agnosticity
+    for c in range(0u32, MAX as u32)
+             .filter_map(|i| from_u32(i))
+             .map(|i| String::from_char(1, i)) {
+        assert_eq!(lev_distance(c[], c[]), 0);
+    }
+
+    let a = "\nMäry häd ä little lämb\n\nLittle lämb\n";
+    let b = "\nMary häd ä little lämb\n\nLittle lämb\n";
+    let c = "Mary häd ä little lämb\n\nLittle lämb\n";
+    assert_eq!(lev_distance(a, b), 1);
+    assert_eq!(lev_distance(b, a), 1);
+    assert_eq!(lev_distance(a, c), 2);
+    assert_eq!(lev_distance(c, a), 2);
+    assert_eq!(lev_distance(b, c), 1);
+    assert_eq!(lev_distance(c, b), 1);
+}
index 18daf6d97e3ad8d9afb16d2ca1b05362507c666d..1ce80b094e10a1b90313313242d305141b53d402 100644 (file)
@@ -5,6 +5,7 @@ pub use self::errors::{CargoResult, CargoError, BoxError, ChainError, CliResult}
 pub use self::errors::{CliError, FromError, ProcessError};
 pub use self::errors::{process_error, internal_error, internal, human, caused_human};
 pub use self::paths::{realpath, join_paths};
+pub use self::lev_distance::{lev_distance};
 pub use self::hex::{to_hex, short_hash};
 pub use self::dependency_queue::{DependencyQueue, Fresh, Dirty, Freshness};
 pub use self::dependency_queue::Dependency;
@@ -26,6 +27,7 @@ pub mod result;
 pub mod to_semver;
 pub mod to_url;
 pub mod toml;
+pub mod lev_distance;
 mod dependency_queue;
 mod sha256;
 mod vcs;